package partner

import (
	"fmt"
	"gitee.com/binny_w/go-util"
	"github.com/casbin/casbin/v2"
	"github.com/casbin/casbin/v2/model"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	_ "github.com/go-sql-driver/mysql"
	"time"
)

// Rbac RBAC结构体
type Rbac struct {
	Adapter    *gormadapter.Adapter
	Enforcer   *casbin.SyncedCachedEnforcer
	SuperAdmin string
	UserNone   string
}

// NewRbac 创建一个实例
func NewRbac(mysqlDsn string, expire time.Duration, superAdmin, userNone string) (*Rbac, error) {
	if superAdmin == "" {
		superAdmin = "SuperAdmin"
	}
	if userNone == "" {
		userNone = "user:none"
	}
	if superAdmin == userNone {
		return nil, fmt.Errorf("wrong super admin or user none: %s, %s", superAdmin, userNone)
	}
	a, err := gormadapter.NewAdapter("mysql", mysqlDsn, true)
	if err != nil {
		return nil, err
	}
	s := `
	[request_definition]
	r = sub, obj, act
	
	[policy_definition]
	p = sub, obj, act
	
	[role_definition]
	g = _, _
	
	[policy_effect]
	e = some(where (p.eft == allow))
	
	[matchers]
	m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
	`
	m, err := model.NewModelFromString(s)
	if err != nil {
		return nil, err
	}
	e, err := casbin.NewSyncedCachedEnforcer(m, a)
	if err != nil {
		return nil, err
	}
	e.SetExpireTime(expire)
	err = e.LoadPolicy()
	if err != nil {
		return nil, err
	}
	_, _ = e.AddRoleForUser(userNone, superAdmin)
	return &Rbac{
		Adapter:    a,
		Enforcer:   e,
		SuperAdmin: superAdmin,
		UserNone:   userNone,
	}, nil
}

// GetAllRoles 获得全部角色名
func (r *Rbac) GetAllRoles() ([]string, error) {
	return r.Enforcer.GetAllRoles()
}

// HasRoleForUser 用户是否属于某角色（不包含隐式）
func (r *Rbac) HasRoleForUser(user, role string) (bool, error) {
	return r.Enforcer.HasRoleForUser(user, role)
}

// AddRoles 添加一个或多个角色
func (r *Rbac) AddRoles(roles ...string) (bool, error) {
	return r.AddRolesForUser(r.UserNone, roles...)
}

// DeleteRoles 删除一个或多个角色
func (r *Rbac) DeleteRoles(roles ...string) error {
	for _, role := range roles {
		if role == r.SuperAdmin || role == r.UserNone {
			continue
		}
		if _, err := r.Enforcer.DeleteRole(role); err != nil {
			return err
		}
	}
	return nil
}

// AddRolesForUser 向用户（或角色）绑定一个或多个角色
func (r *Rbac) AddRolesForUser(user string, roles ...string) (bool, error) {
	if user == r.SuperAdmin {
		return false, fmt.Errorf("user same as super admin: %s, %s", user, r.SuperAdmin)
	}
	if in, _ := util.InArray(r.UserNone, roles); in {
		return false, fmt.Errorf("a role same as user none")
	}
	return r.Enforcer.AddRolesForUser(user, roles)
}

// GetRolesForUser 获得用户的角色（一个或多个）
func (r *Rbac) GetRolesForUser(user string) ([]string, error) {
	return r.Enforcer.GetRolesForUser(user)
}

// GetImplicitRolesForUser 获得用户的角色（一个或多个，包含隐式层级）
func (r *Rbac) GetImplicitRolesForUser(user string) ([]string, error) {
	return r.Enforcer.GetImplicitRolesForUser(user)
}

// DeleteRolesForUser 删除用户的一个或多个角色
func (r *Rbac) DeleteRolesForUser(user string, roles ...string) error {
	for _, role := range roles {
		if _, err := r.Enforcer.DeleteRoleForUser(user, role); err != nil {
			return err
		}
	}
	return nil
}

// ClearRolesForUser 清空用户的角色
func (r *Rbac) ClearRolesForUser(user string) (bool, error) {
	return r.Enforcer.DeleteRolesForUser(user)
}

// DeleteUsers 删除一个或多个用户
func (r *Rbac) DeleteUsers(users ...string) error {
	for _, user := range users {
		if user == r.UserNone || user == r.SuperAdmin {
			continue
		}
		if _, err := r.Enforcer.DeleteUser(user); err != nil {
			return err
		}
	}
	return nil
}

// GetPermissionsForRole 获取角色的权限，不包含隐式
func (r *Rbac) GetPermissionsForRole(role string) ([][]string, error) {
	return r.Enforcer.GetPermissionsForUser(role)
}

// Enforce 验证某个用户或角色，能否对资源进行某项操作
func (r *Rbac) Enforce(role string, vals ...any) (bool, error) {
	if role == r.SuperAdmin {
		return true, nil
	}
	if role == r.UserNone {
		return false, nil
	}
	roles, _ := r.GetImplicitRolesForUser(role)
	if in, _ := util.InArray(r.SuperAdmin, roles); in {
		return true, nil
	}
	all := make([]any, 0)
	all = append(all, role)
	all = append(all, vals...)
	return r.Enforcer.Enforce(all...)
}

// HasPermissionForRole 角色或用户，对某资料是否有操作权限（不包含隐式）
func (r *Rbac) HasPermissionForRole(role string, vals ...string) (bool, error) {
	return r.Enforcer.HasPermissionForUser(role, vals...)
}

// AddPermissionForRole 给角色添加一个资源的操作权限
func (r *Rbac) AddPermissionForRole(role string, vals ...string) (bool, error) {
	return r.AddPermissionsForRole(role, vals)
}

// AddPermissionsForRole 给角色或用户，添加一个或多个资源的操作权限
func (r *Rbac) AddPermissionsForRole(role string, permissions ...[]string) (bool, error) {
	return r.Enforcer.AddPermissionsForUser(role, permissions...)
}

// DeletePermissionForRole 删除角色对资源的操作权限
func (r *Rbac) DeletePermissionForRole(role string, vals ...string) (bool, error) {
	return r.Enforcer.DeletePermissionForUser(role, vals...)
}

// ClearPermissionsForRole 清空角色的权限
func (r *Rbac) ClearPermissionsForRole(role string) (bool, error) {
	return r.Enforcer.DeletePermissionsForUser(role)
}
